//*********************************************************
//
//    Copyright (c) Microsoft. All rights reserved.
//    This code is licensed under the Apache License, Version 2.0.
//    THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
//    ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
//    IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
//    PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************

namespace Microsoft.Research.eResearch.Common.Testing
{
    using System;
    using System.IO;
    using System.Runtime.Serialization;
    using System.Runtime.Serialization.Formatters.Binary;
    using System.Xml.Serialization;

    /// <summary>
    /// Provides static methods to test the round-trip serialization (serialization and deserialization)
    /// of objects in both binary and XML format.
    /// </summary>
    public static class RoundtripSerialization
    {
        /// <summary>
        /// Performs a binary serialization of the input object to a memory stream and then 
        /// returns the deserialized object.
        /// </summary>
        /// <typeparam name="T">The type of the input object.</typeparam>
        /// <param name="input">The input object to serialize.</param>
        /// <returns>The deserialized object.</returns>
        public static T RoundtripBinarySerialization<T>(T input)
        {
            T output;
            using (Stream ms = new MemoryStream())
            {
                IFormatter formatter = new BinaryFormatter();
                formatter.Serialize(ms, input);

                ms.Seek(0, SeekOrigin.Begin);

                output = (T)formatter.Deserialize(ms);
            }

            return output;
        }

        /// <summary>
        /// Performs an XML serialization of the input object to a memory stream and then 
        /// returns the deserialized object.
        /// </summary>
        /// <typeparam name="T">The type of the input object.</typeparam>
        /// <param name="input">The input object.</param>
        /// <returns>The deserialized object.</returns>
        public static T RoundtripXmlSerialization<T>(T input)
        {
            return RoundtripXmlSerialization(input, null);
        }

        /// <summary>
        /// Performs an XML serialization of the input object to a memory stream and then 
        /// returns the deserialized object.
        /// </summary>
        /// <typeparam name="T">The type of the input object.</typeparam>
        /// <param name="input">The input object.</param>
        /// <param name="printXmlMethod">A delegate that is called with the XML text as a parameter. 
        /// Use this hook if you want to inspect this text.</param>
        /// <returns>The deserialized object.</returns>
        public static T RoundtripXmlSerialization<T>(T input, Action<string> printXmlMethod)
        {
            T output;
            using (Stream ms = new MemoryStream())
            {
                XmlSerializer xs = new XmlSerializer(typeof(T));
                xs.Serialize(ms, input);

                ms.Seek(0, SeekOrigin.Begin);

                output = (T)xs.Deserialize(ms);

                if (printXmlMethod != null)
                {
                    ms.Seek(0, SeekOrigin.Begin);
                    StreamReader sr = new StreamReader(ms);
                    string xml = sr.ReadToEnd();
                    printXmlMethod(xml);
                }
            }

            return output;
        }
    }
}
